//////////////////////////////////////////////////////////////////////
//
// NO_Transform.h: interface for the NO_Transform class.
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
#ifndef NO_Transform_H
#define NO_Transform_H

//////////////////////////////////////////////////////////////////////////
#include "NO_Includes.h"

//////////////////////////////////////////////////////////////////////////
class NO_Type;

//////////////////////////////////////////////////////////////////////
// NO_Transform Interface
//////////////////////////////////////////////////////////////////////
class NO_DLL_TAL NO_NoneTransform 
{
public:
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const;
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const;
};

//////////////////////////////////////////////////////////////////////////
// NO_SimpleTransform
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_SimpleTransform
{
protected:
	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const
	{
		return stream.objectBegin(object)
					  .write(*noGetDataException<T>(object))
					  .objectEnd(object);
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const
	{
		return stream.objectBegin(object)
					  .read(*noGetDataException<T>(object))
					  .objectEnd(object);
	}
};

//////////////////////////////////////////////////////////////////////////
// NO_ClassTransform
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ClassTransform
{
protected:
	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const
	{
		return stream.objectBegin(object)
					  .bases(object)
					  .members(object)
					  .objectEnd(object);
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const
	{
		return stream.objectBegin(object)
					  .bases(object)
					  .members(object)
					  .objectEnd(object);
	}
};

//////////////////////////////////////////////////////////////////////////
// NO_ObjectTransform
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ObjectTransform
{
protected:
	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const
	{
		
		stream.objectBegin(object);
		stream.range(*(noGetDataException<T>(object)));
		return stream.objectEnd(object);
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const
	{
		
		stream.objectBegin(object);
		stream.range(*(noGetDataException<T>(object)));
		stream.objectEnd(object);
		return stream;
	}
};

//////////////////////////////////////////////////////////////////////////
// NO_PointerTransform
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_PointerTransform
{
protected:
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const
	{
		
		stream.objectBegin(object);
		stream.range(object.dereference());
		stream.objectEnd(object);
		return stream;
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const
	{
		
		stream.objectBegin(object);
		NO_Boolean create = 0;
		NO_Boolean except = 0;
		NO_Object d;

		try{create = !stream.verify(d=object.dereference());}
		catch(...){create = 1; except = 1; std::cout<<"Exception correct!"<<std::endl;}

		if(create)
		{
			T** o = noGetDataException<T*>(object);
			if(*o&&!except){delete *o;}
			*o = noGetDataException<T>(stream.restore().cast(NO_TypeID<T>::type()));
		}
		stream.range(object.dereference());
		stream.objectEnd(object);
		return stream;
	}
};

//////////////////////////////////////////////////////////////////////////
// NO_FuncPointerTransform
//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_FuncPointerTransform
{
protected:
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const
	{
		stream.objectBegin(object);
		stream.objectEnd(object);
		return stream;
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const
	{
		stream.objectBegin(object);
		stream.objectEnd(object);
		return stream;
	}
};

//////////////////////////////////////////////////////////////////////////
template<class T>
class NO_ContainerFriendHelper
{
protected:
	NO_Object getTObject(T* v) const {return NO_TypeObject<T>(v);}
};

//////////////////////////////////////////////////////////////////////////
// NO_PairTransform
//////////////////////////////////////////////////////////////////////////
template<class Key, class Value>
class NO_PairTransform : public NO_ContainerFriendHelper<Key>, public NO_ContainerFriendHelper<Value>
{
public:
	//////////////////////////////////////////////////////////////////////
	typedef std::pair<Key,Value> T;
	typedef NO_TypeObject<Key> KeyObj;
	typedef NO_TypeObject<Value> ValObj;
	
protected:
	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const
	{
		T* pair = noGetDataException<T>(object);
		stream.objectBegin(object);
		
		NO_Object k = NO_ContainerFriendHelper<Key>::getTObject(&pair->first);  
		k.getType().output(k,stream);
		
		NO_Object v = NO_ContainerFriendHelper<Value>::getTObject(&pair->second); 
		v.getType().output(v,stream);
		
		return stream.objectEnd(object);
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const
	{
		T* pair = noGetDataException<T>(object);
		stream.objectBegin(object);
	
		NO_Object k = NO_ContainerFriendHelper<Key>::getTObject(&pair->first);  
		k.getType().input(k,stream);
		
		NO_Object v = NO_ContainerFriendHelper<Value>::getTObject(&pair->second); 
		v.getType().input(v,stream);
		
		return stream.objectEnd(object);
	}
};

//////////////////////////////////////////////////////////////////////////
// NO_ContainerTransform
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
template<class T, class V>
class NO_ContainerTransform : public NO_ContainerFriendHelper<V>
{
	//////////////////////////////////////////////////////////////////////
	typedef typename T::iterator		Iterator;
	typedef typename T::const_iterator	ConstIterator;
	typedef std::insert_iterator<T>	Inserter;
	
protected:
	//////////////////////////////////////////////////////////////////////////
	// use
	//////////////////////////////////////////////////////////////////////////
	
	//////////////////////////////////////////////////////////////////////
	NO_OArchive& outputImpl(NO_Object& object, NO_OArchive& stream) const
	{
		T* con = noGetDataException<T>(object);
		NO_UInt32 size = con->size();
		NO_OArchive& arch = stream.objectBegin(object);

		arch.write(size);
		const NO_Type& type = NO_TypeID<V>::type();
		Iterator iter = con->begin(); 
		Iterator end = con->end();
		while(iter!=end)
		{
			NO_Object tObj = getTObject(reinterpret_cast<V*>(&(*iter)));
			type.output(tObj,arch);
			++iter;
		}

		stream.objectEnd(object);
		return stream;
	}
	
	//////////////////////////////////////////////////////////////////////
	NO_IArchive& inputImpl(NO_Object& object, NO_IArchive& stream) const
	{
		T* con = noGetDataException<T>(object); 

		NO_UInt32 size = 0;
		stream.objectBegin(object);
		stream.read(size);

		Inserter iIter = std::inserter((*con),con->begin());
		for (NO_UInt32 i = 0; i < size; ++i)
		{
			const NO_Type& type = NO_TypeID<V>::type();
			NO_TypeObject<V> tObj;
			type.input(tObj,stream);
			iIter = *noGetDataException<V>(tObj);
		}

		stream.objectEnd(object);
		
		return stream;
	}
};

#endif
